#ifndef SEARCHCONTROLLER_H
#define SEARCHCONTROLLER_H

#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QDir>

#include <queue>
#include <set>
#include <stack>

#include "SearchTask.h"
#include "ISearchControllerThreadCallback.h"

#include <boost/utility.hpp>

class SearchControllerThread;
class IConfig;

/** Main controller for search

 */
class SearchController : public QThread
                       , public ISearchControllerThreadCallback
                       , private boost::noncopyable
{
Q_OBJECT
public  :
    SearchController(QObject *parent, IConfig *config);
    ~SearchController();

    /** Run folder scan */
    void scanFolder(const QString & folder);

    /** Run file scan */
    void scanFile(const QString & filename);

    /** Run bytearray scan */
    void scanByteArray(QByteArray & byteArray);

    /** Interrupt processing

     */
    void interrupt();

    /** @name inherited from SearchControllerThreadCallback */
    // @{
    virtual void onProgress(SearchTaskPtr task, SearchControllerThread *thread, float progress);
    virtual void guidFound(SearchTaskPtr task, SearchControllerThread *thread,
                           const std::string & guid);
    virtual void notFound(SearchTaskPtr task, SearchControllerThread *thread);
    virtual void onError(SearchTaskPtr task, SearchControllerThread *thread,
                         const std::string & errMsg);
    virtual void onInterrupted(SearchTaskPtr task, SearchControllerThread *thread);
    // @}

private :

    /** Work function. Inherited from QThread */
    void run();

    /** Init specified threads count */
    void initThreads(int count);

    /** Gets next task

        @return
            return NULL piinter if tasks is over
            next task object
     */
    SearchTaskPtr getNextTask();

    /** Signal to increment progress */
    void signalIncProgress();

    /** Direcotry scaner suplementary struct */
    struct FileScanStruct
    {
        QFileInfoList m_infoList;
        QFileInfoList::Iterator m_iter;

        FileScanStruct(const QFileInfoList & infoList)
            : m_infoList(infoList)
        {
            m_iter = m_infoList.begin();
        }
    };

    typedef boost::shared_ptr<struct FileScanStruct> FileScanStructPtr;
    typedef std::stack<FileScanStructPtr> FolderScanerStack;

    /** Scan folder
        If files is found id creates SearchTasks for fiels and add  it to m_taskQueue
        Function monitor also m_stopRequested flag and return if stop was requested

        @return
            added files count
     */
    int recursiveScan(FolderScanerStack &stack, int limit);

    FolderScanerStack m_folderScanerStack;

    typedef std::queue<SearchTaskPtr> TaskQueue;
    typedef std::vector<SearchControllerThread*> ControllerThreadVector;

    ControllerThreadVector m_workThreads;

    /** Available tasks */
    TaskQueue m_taskQueue;

    QString m_searchPath;
    SearchType m_searchType;

    /** Stop request flag */
    QAtomicInt m_stopRequested;

    QWaitCondition m_Event;
    QMutex m_mutex;

    /** 1- if search scope is defined
        0 - total coutn os not defined
     */
    QAtomicInt m_wholeProgressDefined;
    int m_totalScanObjects;
    QAtomicInt m_completedObjectsCount;

    QAtomicInt m_activeThreads;

    IConfig *m_config;

signals:
    /**
    * @brief change state of progress bar
    * @param progressValue - count task complete now
    */
   void sigProgress(float progressValue);

   /**
    * @brief print value to frame log
    * @param fileName - name's file scanned
    * @param value - string to print
    */
   void sigFoundGUID(QString fileName, QString guid);

   /**
    * @param fileName - name's file scanned
    */
   void sigNotFoundGUID(QString fileName);

   /**
    * @brief print errors to frame log
    * @param fileName - name's file scanned
    * @param errMessage - description error
    */
   void sigError(QString fileName, QString errMessage);

   /**
    * @brief print about interrupted scan process to frame log
    */
   void sigInterrupted();

};

#endif // SEARCHCONTROLLER_H
